8

场景

我们的资源来自网络的四面八方,所以难免需要用上跨域,业界也有非常多跨域的解决方案,这次我是来说说跨域与状态码之间的一个问题。

问题

当我们的 URL 地址返回的状态码是 400、403、404、500 的时候,跨域的资源是不会跟随返回的,也就是说,即便是 Nginx 上配置了 add_header 关键字,也不会随着内容返回而返回。

举个例子说:

add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods *;

当我们在请求对应地址的时候,理应是会返回已经配置好的头部信息,但是我们来看看最终的结果。

200
HTTP/1.1 200 OK
Server: openresty/1.11.2.2
Date: Fri, 26 Jan 2018 08:46:39 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 558
Last-Modified: Tue, 28 Mar 2017 01:13:24 GMT
Connection: keep-alive
ETag: "58d9b8b4-22e"
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Accept-Ranges: bytes

内容无误。

404
HTTP/1.1 404 Not Found
Server: openresty/1.11.2.2
Date: Fri, 26 Jan 2018 08:47:18 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 175
Connection: keep-alive

神奇了,这里404状态码下面居然自定义的响应头消失了。

原因与解决方式

留意 Nginx 文档上说的:

Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0). The value can contain variables.

意思就是说,add_header 只会追加到以上响应状态码的响应头上面。

因为咱们的 API 有各种的状态码返回,那么其他状态码下,该怎么办? 大家留意文档上有一个参数。

Syntax:    add_trailer name value [**always**];
Default:    —
Context:    http, server, location, if in location
This directive appeared in version 1.13.2.

你会发现有个 [always] 参数,那么这个参数,就是让你的配置头,应用在所有的影响上面去。

将参数添加进去:

add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods * always;

重启 nginx 服务器后重试一下.

200
HTTP/1.1 200 OK
Server: openresty/1.11.2.2
Date: Fri, 26 Jan 2018 09:01:36 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 558
Last-Modified: Tue, 28 Mar 2017 01:13:24 GMT
Connection: keep-alive
ETag: "58d9b8b4-22e"
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Accept-Ranges: bytes

200请求没变化,一切正常。

404
HTTP/1.1 404 Not Found
Server: openresty/1.11.2.2
Date: Fri, 26 Jan 2018 09:02:12 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 175
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *

现在 404 也正确了。我们的跨域也正是配置完成。

关于 OPTIONS 请求

当我们前端发起跨域请求的时候,会事先发起一次 OPTIONS 请求,以用来查询该接口是否支持跨域和对应的请求方法。

在配置方面可以这么做。

if ($request_method = OPTIONS) {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods *;
    add_header Access-Control-Allow-Credentials true;
    return 204;
   }

当然我这里的 * 这么用是不好的,你需要对应域名去配置。

另外PHP方面我们也提供了一个 CORS 的扩展库,可以直接在fastd中使用。

github: cors-provider


黄总
778 声望110 粉丝

不能因为菜刀能砍人你就以为菜刀只能砍人